/** !Double linked list structure handling macros.

This module conatins some convenience macros for handling double
linked list structures. */

#ifndef MX__DEDS_DLLIST_HEADER
#define MX__DEDS_DLLIST_HEADER

#include <assert.h>

#ifdef __cplusplus
extern "C" {
#endif

/**type !Double linked list
This macro declares a double linked list structure.  The list
surrounding type can then be manipulated by the other mx_dllist_* and 
MX_DLLIST_* macros.  The type should be initialized with all zeros. */
#define MX_DLLIST(type)    \
typedef struct {           \
    type *mx__dllistfirst; \
    type *mx__dllistlast;  \
}

/**type !Elements for a double linked list
This macro declares elements for a double linked list structure.
This delcaration must be included in a struct with an appropriate type.  The
surrounding type can then be manipulated by the other mx_dllist_* and 
MX_DLLIST_* macros.  The surrounding type should be initialized with all 
zeros. */
#define MX_DLLIST_ELEM(type) \
    type *mx__dllistfirst;   \
    type *mx__dllistlast

/**type !Elements for a double linked list node
This macro declares elements for a double linked list node
structure.  This delcaration must be included in a struct with an appropriate 
type.  The surrounding type can then be manipulated by the other mx_dllist_* 
and MX_DLLIST_* macros.  The surrounding type should be initialized with all
zeros. */
#define MX_DLLIST_NODE(type,list) \
    list *mx__dllistlist;         \
    type *mx__dllistprev;         \
    type *mx__dllistnext

/** !Insert a double linked element into a double linked list
The inserted element is placed at the end of the list. */
#define MX_DLLIST_APPEND(o,p)                             \
    do {                                                  \
        assert(o);                                        \
        assert(!(o)->mx__dllistlist);                     \
        assert(p);                                        \
        if (p) {                                          \
            (o)->mx__dllistlist = (p);                    \
            if ((p)->mx__dllistlast)                      \
                (p)->mx__dllistlast->mx__dllistnext = (o);\
            (o)->mx__dllistprev = (p)->mx__dllistlast;    \
            (o)->mx__dllistnext = 0;                      \
            (p)->mx__dllistlast = (o);                    \
            if (!(p)->mx__dllistfirst)                    \
                (p)->mx__dllistfirst = (o);               \
        }                                                 \
    } while (0)

/** !Insert a double linked element into a double linked list
The inserted element is placed at the beginning of the list. */
#define MX_DLLIST_PREPEND(o,p)                             \
    do {                                                   \
        assert(o);                                         \
        assert(!(o)->mx__dllistlist);                      \
        assert(p);                                         \
        if (p) {                                           \
            (o)->mx__dllistlist = (p);                     \
            if ((p)->mx__dllistfirst)                      \
                (p)->mx__dllistfirst->mx__dllistprev = (o);\
            (o)->mx__dllistprev = 0;                       \
            (o)->mx__dllistnext = (p)->mx__dllistfirst;    \
            (p)->mx__dllistfirst = (o);                    \
            if (!(p)->mx__dllistlast)                      \
                (p)->mx__dllistlast = (o);                 \
        }                                                  \
    } while (0)

/** !Remove a double linked list element from its list */
#define MX_DLLIST_REMOVE(o)                         \
    do {                                            \
        assert(o);                                  \
        assert(o->mx__dllistlist);                          \
        if ((o) && ((o)->mx__dllistlist)) {                 \
            assert(o->mx__dllistlist->mx__dllistfirst);             \
            assert(o->mx__dllistlist->mx__dllistlast);              \
            if ((o)->mx__dllistlist->mx__dllistlast == (o))         \
                (o)->mx__dllistlist->mx__dllistlast = (o)->mx__dllistprev;  \
            if ((o)->mx__dllistlist->mx__dllistfirst == (o))        \
                (o)->mx__dllistlist->mx__dllistfirst = (o)->mx__dllistnext; \
            if ((o)->mx__dllistprev)                        \
                (o)->mx__dllistprev->mx__dllistnext = (o)->mx__dllistnext;  \
            if ((o)->mx__dllistnext)                        \
                (o)->mx__dllistnext->mx__dllistprev = (o)->mx__dllistprev;  \
            (o)->mx__dllistnext = 0;                        \
            (o)->mx__dllistprev = 0;                        \
            (o)->mx__dllistlist = 0;                        \
        }                                           \
    } while (0)

/** !First element of a double linked list. */
#define mx_dllist_first(o)   ((o)->mx__dllistfirst)

/** !Last element of a double linked list. */
#define mx_dllist_last(o)   ((o)->mx__dllistlast)

/** !Next element in the double linked list.*/
#define mx_dllist_next(o)   ((o)->mx__dllistnext)

/** !Previous element in the double linked list.*/
#define mx_dllist_prev(o)   ((o)->mx__dllistprev)

/** !List that an element is contained in. */
#define mx_dllist_list(o)   ((o)->mx__dllistlist)

#ifdef __cplusplus
}
#endif
#endif
/*
    DEDS
    Data structures and utility functions for C
    Copyright (C) 2006 Douglas Eleveld

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
*/
